//
//  PPAlbumSynchronizer.m
//  pickpic
//
//  Created by Jinxiao on 9/5/16.
//  Copyright © 2016 MicroDream. All rights reserved.
//

#import "PPAlbumSynchronizer.h"

#import "PPNetworkService.h"

#import "PPAlbumModel.h"

@interface PPAlbumSynchronizer ()
@end

@implementation PPAlbumSynchronizer

+ (instancetype)sharedInstance {
    static id instance;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        instance = self.new;
    });

    return instance;
}

- (instancetype)init {
    self = [super init];

    return self;
}

- (void)synchronizeDeletionsIfNeededWithCompletion:(void (^)(NSError *error))completion {

    __block NSError *error_ = nil;

    dispatch_group_t group = dispatch_group_create();

    // 先把本地异步删除的相册同步成功，其中可能包括更新但未上传、创建但未上传的相册
    NSArray <PPAlbumModel *> *deletedAlbums = [PPAlbumModel where:@{@"status" : @(PPAlbumStatusDeleted)}];

    [deletedAlbums enumerateObjectsUsingBlock:^(PPAlbumModel *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {

        PPAlbumID albumID = obj.albumID.integerValue;

        dispatch_group_enter(group);
        [PPNetworkService deleteAlbumWithAlbumID:albumID callback:^(id data, NSError *error) {

            if(error == nil) {

                PPAlbumModel *deletedAlbum = [PPAlbumModel find:@{@"albumID" : @(albumID)}];
                [deletedAlbum delete];
                [deletedAlbum.managedObjectContext saveContext];

            } else {

                error_ = error;

            }

            dispatch_group_leave(group);

        }];

    }];


    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

        !completion ? : completion(error_);

    });

}

- (void)synchronizeCreationsIfNeededWithCompletion:(void (^)(NSError *error))completion {
    __block NSError *error_ = nil;

    dispatch_group_t group = dispatch_group_create();


    NSArray <PPAlbumModel *> *createdAlbums = [PPAlbumModel where:@{@"status" : @(PPAlbumStatusCreated)}];

    [createdAlbums enumerateObjectsUsingBlock:^(PPAlbumModel *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {

        NSManagedObjectID *objectID = obj.objectID;

        NSMutableArray *tags = [NSMutableArray array];
        [obj.tags enumerateObjectsUsingBlock:^(PPAlbumTagModel *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
            [tags addObject:[NSString stringWithFormat:@"%li", (long)obj.tagID]];
        }];

        dispatch_group_enter(group);
        [PPNetworkService createAlbumWithTitle:obj.title desc:obj.desc privacy:obj.privacy privacySettings:@[] commentSetting:obj.permission tags:tags pictures:@[] order:obj.order callback:^(id data, NSError *error) {
            if(error == nil) {

                NSManagedObjectContext *context = [NSManagedObjectContext threadObjectContext];

                PPAlbumModel *createdAlbum = [context objectWithID:objectID];
                createdAlbum.albumID = [data validNumberForKey:@"albumid"];
                createdAlbum.status = @(PPAlbumStatusUploaded);

                [context saveContext];

            } else {

                error_ = error;

            }

            dispatch_group_leave(group);
        }];

    }];

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

        !completion ? : completion(error_);

    });
}

- (void)synchronizeModificationsIfNeededWithCompletion:(void (^)(NSError *error))completion {
    __block NSError *error_ = nil;

    dispatch_group_t group = dispatch_group_create();


    NSArray <PPAlbumModel *> *modifiedAlbums = [PPAlbumModel where:@{@"status" : @(PPAlbumStatusModified)}];

    [modifiedAlbums enumerateObjectsUsingBlock:^(PPAlbumModel *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {

        PPAlbumID albumID = obj.albumID.integerValue;

        NSMutableArray *tags = [NSMutableArray array];
        [obj.tags enumerateObjectsUsingBlock:^(PPAlbumTagModel *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
            [tags addObject:[NSString stringWithFormat:@"%li", (long)obj.tagID]];
        }];

        dispatch_group_enter(group);

        [PPNetworkService updateAlbumWithAlbumID:@(albumID) albumTitle:obj.title albumDesc:obj.desc privacy:obj.privacy privacySettings:@[] commentSetting:obj.permission coverImg:obj.coverURL tags:tags order:obj.order callback:^(id data, NSError *error) {
            if(error == nil) {

                PPAlbumModel *modifiedAlbum = [PPAlbumModel find:@{@"albumID" : @(albumID)}];
                modifiedAlbum.status = @(PPAlbumStatusUploaded);

                [modifiedAlbum.managedObjectContext saveContext];

            } else {

                error_ = error;

            }

            dispatch_group_leave(group);
        }];

    }];

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

        !completion ? : completion(error_);

    });
}

- (void)synchronizeLocalAlbumsIfNeededWithCompletion:(void (^)(NSError *error))completion {

    // 先把本地异步删除的相册同步成功，其中可能包括更新但未上传、创建但未上传的相册

    [self synchronizeDeletionsIfNeededWithCompletion:^(NSError *error) {

        if(error != nil) {
            !completion ? : completion(error);
        } else {


            // 剩下的异步操作包含创建未上传和修改未上传两种，先把创建未上传的相册上传，得到相册id

            [self synchronizeCreationsIfNeededWithCompletion:^(NSError *error) {

                if(error != nil) {
                    !completion ? : completion(error);
                } else {

                    // 最后开始同步相册变更
                    [self synchronizeModificationsIfNeededWithCompletion:^(NSError *error) {
                        !completion ? : completion(error);
                    }];

                }
            }];

        }
    }];
}

- (void)synchronizeRemoteAlbumsIfNeededWithCompletion:(void (^)(NSError *error))completion {

    NSMutableArray <PPAlbumModel *> *remoteAlbums = [NSMutableArray array];

    [PPNetworkService fetchMyAlbumsWithKeyword:nil ablumIDs:nil tagID:nil isHotTag:nil callback:^(id data, NSError *error) {

        if(error == nil) {

            NSArray <PPAlbumModel *> *localAlbums = [PPAlbumModel where:@{@"status": @(PPAlbumStatusUploaded)}];

            for(NSDictionary *result in [data validArrayForKey:@"ablums"]) {

                PPAlbumID albumID = [result validNumberForKey:@"albumid"].integerValue;

                PPAlbumModel *album = [PPAlbumModel existingAlbumForAlbumID:albumID];
                album.coverURL = [result validStringForKey:@"coverImg"];
                album.title = [result validStringForKey:@"title"];
                album.desc = [result validStringForKey:@"description"];
                album.order = [result validNumberForKey:@"order"];
                album.privacy = [result validNumberForKey:@"privacy"];
                album.permission = [result validNumberForKey:@"comment"];


                // Image Merge.

                NSArray <PPAlbumImageModel *> *localImages = album.images;
                NSMutableArray <PPAlbumImageModel *> *remoteImages = [NSMutableArray array];

                for(NSDictionary *picture in [result validArrayForKey:@"pictures"]) {
                    PPAlbumImageID imageID = [picture validNumberForKey:@"pictureid"].integerValue;

                    PPAlbumImageModel *image = [PPAlbumImageModel existingAlbumImageForImageID:imageID];
                    image.albumID = @(albumID);
                    image.like = [picture validNumberForKey:@"like"];
                    image.comment = [picture validNumberForKey:@"comment"];
                    image.url = [picture validStringForKey:@"url"];
                    [remoteImages addObject:image];
                }

                NSMutableArray <PPAlbumImageModel *> *deleteImages = [NSMutableArray array];

                for(PPAlbumImageModel *localImage in localImages) {
                    BOOL exists = NO;

                    for(PPAlbumImageModel *remoteImage in remoteImages) {
                        if(remoteImage.imageID == localImage.imageID) {
                            exists = YES;
                            break;
                        }
                    }

                    if(!exists) {
                        [deleteImages addObject:localImage];
                    }
                }

                for(PPAlbumImageModel *deleteImage in deleteImages) {
                    [deleteImage delete];
                }

                // Tag Merge.

                NSArray <PPAlbumTagModel *> *localTags = album.tags;
                NSMutableArray <PPAlbumTagModel *> *remoteTags = [NSMutableArray array];

                for(NSDictionary *tagg in [result validArrayForKey:@"tags"]) {
                    PPAlbumTagID tagID = [tagg validNumberForKey:@"tagid"].integerValue;

                    PPAlbumTagModel *tag = [PPAlbumTagModel existingAlbumTagForTagID:tagID];
                    tag.albumID = @(albumID);
                    tag.name = [tagg validStringForKey:@"name"];
                    [remoteTags addObject:tag];
                }

                NSMutableArray <PPAlbumTagModel *> *deleteTags = [NSMutableArray array];

                for(PPAlbumTagModel *localTag in localTags) {
                    BOOL exists = NO;

                    for(PPAlbumTagModel *remoteTag in remoteTags) {
                        if(remoteTag.tagID == localTag.tagID) {
                            exists = YES;
                            break;
                        }
                    }

                    if(!exists) {
                        [deleteTags addObject:localTag];
                    }
                }

                for(PPAlbumTagModel *deleteTag in deleteTags) {
                    [deleteTag delete];
                }

                [remoteAlbums addObject:album];
            }

            NSMutableArray <PPAlbumModel *> *deleteAlbums = [NSMutableArray array];

            for(PPAlbumModel *localAlbum in localAlbums) {

                BOOL exists = NO;

                for(PPAlbumModel *remoteAlbum in remoteAlbums) {
                    if(remoteAlbum.albumID == localAlbum.albumID) {
                        exists = YES;
                        break;
                    }
                }
                
                if(!exists) {
                    [deleteAlbums addObject:localAlbum];
                }
            }
            
            for(PPAlbumModel *deleteAlbum in deleteAlbums) {
                [deleteAlbum delete];
            }
            
            [[NSManagedObjectContext threadObjectContext] saveContext];
        }
    }];

}

- (void)synchronizeWithCompletion:(void (^)(NSError *error))completion {

    // 先将本地的更新同步到服务器，再将服务器的数据更新到本地

    [self synchronizeLocalAlbumsIfNeededWithCompletion:^(NSError *error) {

        if(error != nil) {
            !completion ?: completion(error);
        } else {

            [self synchronizeRemoteAlbumsIfNeededWithCompletion:^(NSError *error) {
                !completion ?: completion(error);
            }];

        }
    }];
}

@end
